package com.sun.controller;


import cn.hutool.json.JSONUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sun.common.QueryPageParam;
import com.sun.common.Result;
import com.sun.common.UploadDataListener;
import com.sun.deploy.net.URLEncoder;
import com.sun.entity.*;
import com.sun.mapper.GoodsMapper;
import com.sun.mapper.StorageMapper;
import com.sun.service.GoodsService;
import com.sun.service.RecordService;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import static java.lang.Thread.sleep;

/**
 * <p>
 * 前端控制器：物品管理
 * </p>
 *
 * @author rabbiter
 * @since 2023-01-06
 */
@RestController
@RequestMapping("/goods")
public class GoodsController {
    @Autowired
    private GoodsService goodsService;
    @Autowired
    private RecordService recordService;
    @Autowired
    private GoodsMapper goodsMapper;
    @Autowired
    private StorageMapper storageMapper;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private SqlSessionFactory sqlSessionFactory;

    private static final ExecutorService executorService = Executors.newFixedThreadPool(5); // 创建一个固定大小的线程池
    /*
     * 新增物品
     * @author rabbiter
     * @date 2023/1/6 12:12
     */
    @PostMapping("/save")
    public Result save(@RequestBody Goods goods) {
        return goodsService.save(goods) ? Result.success() : Result.fail();
    }

    /*
     * 更新物品
     * @author rabbiter
     * @date 2023/1/6 13:22
     */
    @PostMapping("/update")
    public Result update(@RequestBody Goods goods) throws InterruptedException {
        //权限系统
        String json = (String) redisTemplate.opsForValue().get("user");
        User user1 = JSONUtil.toBean(json, User.class);
        String key = "lock:goods:" + goods.getId();
        Boolean lock = redisTemplate.opsForValue().setIfAbsent(key, user1.getId(), 10, TimeUnit.SECONDS);
        if (lock) {
            String lockValue = (String) redisTemplate.opsForValue().get(key);
            boolean b = goodsService.updateById(goods);
            // 5.如果锁的值和设置的值相等，则清理自己的锁
            if (user1.getId().equals(lockValue)) {
                System.out.println("清理锁：" + lockValue);
                redisTemplate.delete(key);
            }
            return b ? Result.success() : Result.fail();
        } else {
            System.out.println("抢占失败，等待锁释放");
            // 4.休眠一段时间
            sleep(100);
            // 5.抢占失败，等待锁释放
            return goodsService.updateById(goods) ? Result.success() : Result.fail();
        }
    }

    /*
     * 删除物品
     * @author rabbiter
     * @date 2023/1/6 13:24
     */
    @GetMapping("/del")
    public Result del(@RequestParam String id) {
        return goodsService.removeById(id) ? Result.success() : Result.fail();
    }

    /*
     * 模糊查询：根据输入查询物品并以分页的形式展示
     * @author rabbiter
     * @date 2023/1/6 13:31
     */
    @PostMapping("/listPage")
    public Result listPage(@RequestBody QueryPageParam query, HttpSession session) {

//        User userBySession = UserUntil.getUserBySession(session);
        //权限系统
        String json = (String) redisTemplate.opsForValue().get("user");
        User user1 = JSONUtil.toBean(json, User.class);

        Integer id = user1.getId();
        String user1Name = user1.getName();
        Integer roleId = user1.getRoleId();

        HashMap param = query.getParam();
        String name = (String) param.get("name");
        String cell = (String) param.get("cell");
        String goodstype = (String) param.get("goodstype");
        String storage = (String) param.get("storage");

        Page<Goods> page = new Page();
        page.setCurrent(query.getPageNum());
        page.setSize(query.getPageSize());

        LambdaQueryWrapper<Goods> queryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(name) && !"null".equals(name)) {
            queryWrapper.like(Goods::getName, name);
        }
        if (StringUtils.isNotBlank(goodstype) && !"null".equals(goodstype)) {
            queryWrapper.like(Goods::getGoodstype, goodstype);
        }
        if (StringUtils.isNotBlank(storage) && !"null".equals(storage)) {
            queryWrapper.like(Goods::getStorage, storage);
        }
        if (StringUtils.isNotBlank(cell) && !"null".equals(cell)) {
            queryWrapper.like(Goods::getCell, cell);
        }

        if (user1.getRoleId()==2){
            List<String> allCellForAdmin = storageMapper.getAllCellForAdmin2(user1.getId(), user1Name);
            if (allCellForAdmin.size()==1){
                queryWrapper.eq(Goods::getCell,allCellForAdmin.get(0));
            }else if (allCellForAdmin.size()==2){
                queryWrapper.eq(Goods::getCell,allCellForAdmin.get(0)).or().eq(Goods::getCell,allCellForAdmin.get(1));
            }


        }




        IPage result = goodsService.pageCC(page, queryWrapper);

        List<Goods> records = result.getRecords();
        return Result.success(records, result.getTotal());

//        if (roleId == 2) {
//            List<String> storages = storageMapper.selectStorage(id, user1Name);
//            if (storages != null && storages.size() != 0) {
//                for (String s : storages) {
//                    Iterator<Goods> iterator = records.iterator();
//                    while (iterator.hasNext()) {
//                        Goods goods = iterator.next();
//                        if (!s.equals(goods.getCell())) {
//                            iterator.remove();
//                        }
//                    }
//                }
//                return Result.success(records, result.getTotal());
//            } else {
//                return Result.fail(500, "该用户无权限");
//            }
//
//        } else {
//            return Result.success(records, result.getTotal());
//        }

    }

    @GetMapping("/download")
    public void downloadFile(HttpServletResponse response) throws IOException {
        // 这里注意 有同学反应使用swagger 会导致各种问题，请直接用浏览器或者用postman
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

        //权限系统
        String json = (String) redisTemplate.opsForValue().get("user");
        User user = JSONUtil.toBean(json, User.class);
        String name = user.getName();
        //获取管理的仓库
        List<String> strings = storageMapper.selectStorage(user.getId(), name);

        QueryWrapper<Goods> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("cell", strings);


//        // 假设你已经有了一个名为goodsList的List<Goods>对象
//        List<Goods> goodsList = goodsService.getMuban();

        List<Goods> goodsList = goodsMapper.selectList(queryWrapper);

        for (Goods goods : goodsList) {
            Storage storageById = goodsService.getStorageById(goods.getStorage());
            goods.setStorage(storageById.getName());
            goods.setCell(storageById.getCell());
            Goodstype goodstype = goodsService.getGoodstype(goods.getGoodstype());
            goods.setGoodstype(goodstype.getName());
        }

        // 使用EasyExcel的write()方法将数据写入到OutputStream中
        // 这将创建一个新的Excel表格，使用Goods类的字段作为列标题，goodsList中的每个元素作为新的行
        EasyExcel.write(response.getOutputStream(), Goods.class).sheet("模板").doWrite(goodsList);
    }

    @PostMapping("/upload")
    @ResponseBody
    public Result upload(MultipartFile file) throws IOException {
        List<Record> records = new ArrayList<>();
        UploadDataListener listener = new UploadDataListener(goodsMapper);
        EasyExcel.read(file.getInputStream(), Goods.class, listener).sheet().doRead();
        List<Goods> goodsList = listener.getGoodsList();
        for (Goods goods : goodsList) {
            Integer id = goods.getId();
            Integer count = goods.getCount();
            if (count != null && count != 0) {
                Record record = new Record();
                record.setCount(count);
                record.setGoods(id);
                if (count > 0) {
                    record.setRemark("入库");
                } else {
                    record.setRemark("出库");
                }
                String json = (String) redisTemplate.opsForValue().get("user");
                User user1 = JSONUtil.toBean(json, User.class);
                Integer id1 = user1.getId();
                record.setAdminId(id1);
                record.setAction("1");
                record.setUserid(id1);
                record.setCell(goods.getCell());
//                save(record);
                records.add(record);
            }

            //符合条数，保存
            if (records.size()>=100){
                executorService.submit(() -> {
                    save(records);
                });
                records.clear();
            }
        }
        //保存剩余的数据
        save(records);

        return Result.success();
    }
    public void save(List<Record> records) {
        SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
        GoodsMapper mapper = sqlSession.getMapper(GoodsMapper.class);
        for (Record record : records) {
            Goods goods = goodsService.getById(record.getGoods());
            int n = record.getCount();
            if ("2".equals(record.getAction())) {
                n = -n;
                record.setCount(n);
            }
            int num = goods.getCount() + n;
            if (num < 0) {
                return;
            }
            goods.setCount(num);
            mapper.updateById(goods);
            record.setCreatetime(LocalDateTime.now());
            recordService.save(record);
        }
        sqlSession.flushStatements();
    }
    public void save(Record record) {
        Goods goods = goodsService.getById(record.getGoods());
        int n = record.getCount();
        // 出库
        if ("2".equals(record.getAction())) {
            n = -n;
            record.setCount(n);
        }

        int num = goods.getCount() + n;
        if (num < 0) {
            return;
        }
        goods.setCount(num);
        goodsService.updateById(goods);
        record.setCreatetime(LocalDateTime.now());
        recordService.save(record);
    }


}
